package com.lanjiyin.cloud.question.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.lanjiyin.cloud.common.constant.RestCodeConstants;
import com.lanjiyin.cloud.common.msg.Result;
import com.lanjiyin.cloud.common.util.security.SignUtil;
import com.lanjiyin.cloud.question.config.SecretConfiguration;

import io.micrometer.core.ipc.http.HttpSender.Method;
import lombok.extern.slf4j.Slf4j;

/**
 * 验证签名过滤器
 * @author tudaojun
 *
 */
@Slf4j
@Component("signFilter")
public class SignFilter implements Filter {
	@Autowired
	private SecretConfiguration secretConfig;

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		String uri = req.getRequestURI();
		if (req.getMethod().equals(Method.POST.toString())
				&& (uri.indexOf("/api/feign/") < 0 && uri.indexOf("/manage/") < 0 && uri.indexOf("/frount") < 0 )) {
			// 校验时间戳
//			if(!verifyTimeSpan(req)) {
//				log.warn(uri +  "======>请求超时");
//				String error = "请求消息超时失效!";
//				Result<String> respResult = new Result<>();
//				respResult.setStatus(RestCodeConstants.TOKEN_FORBIDDEN_CODE);
//				respResult.setMessage(error);
//				errorResponse(resp, respResult);
//				return;
//			}
			if (!verifySign(req)) {
				log.error(uri + "======>验签失败");
				String error = "验签失败!";
				Result<String> respResult = new Result<>();
				respResult.setCode(RestCodeConstants.TOKEN_FORBIDDEN_CODE);
				respResult.setMessage(error);
				errorResponse(resp, respResult);
				return;
			}
		}
		chain.doFilter(req, resp);
	}

	private void errorResponse(HttpServletResponse response, Result<String> msg) throws IOException {
		response.setContentType("text/plain; charset=UTF-8");
		PrintWriter out = response.getWriter();
		out.println(JSON.toJSONString(msg));
		out.flush();
		out.close();
	}

	/**
	 * @Title: 验签 @Description: TODO(这里用一句话描述这个方法的作用) @param: @param
	 *         req @param: @return @return: boolean @throws
	 */
	public boolean verifySign(HttpServletRequest req) {
		String sign = req.getParameter("sign");
		if (StringUtils.isNotBlank(sign)) {
			Map<String, Object> parameters = new TreeMap<>();
			Enumeration<String> enumNames = req.getParameterNames();
			if(!enumNames.hasMoreElements()) {
				return false;
			}
			while (enumNames.hasMoreElements()) {
				String paramName = (String) enumNames.nextElement();
				String paramValue = req.getParameter(paramName);
				// 形成键值对应的map
				parameters.put(paramName, paramValue);
			}
			boolean flag = SignUtil.verifySign(secretConfig.getSecret(), parameters, sign, "&", "sign");
			if(!flag) {
				log.error("验签失败："+JSON.toJSONString(parameters)+"");
			}
			return flag;
		} else {
			return false;
		}
	}

	/**
	 * 验证请求时间(大于40S将返回请求失效信息) @Title: verifyTimeSpan @Description:
	 * TODO(这里用一句话描述这个方法的作用) @param: @param req @param: @return @return:
	 * boolean @throws
	 */
	public boolean verifyTimeSpan(HttpServletRequest req) {
		String timespan = req.getParameter("timespan");
		if (StringUtils.isBlank(timespan))
			return false;
		try {
			long orgTimeSpan = Long.parseLong(timespan);
			long nowTimeSpan = new Date().getTime();
			long diffTimespan = nowTimeSpan - orgTimeSpan;
			if (diffTimespan < 0)
				return false;
			long seconds = diffTimespan / 1000;
			if (seconds > 60) {
				return false;
			} else {
				return true;
			}
		} catch (Exception se) {
			log.error("时间戳转换异常", se);
			return false;
		}
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		

	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}
}
